package com.codename1.samples;

import com.codename1.components.SpanLabel;
import com.codename1.components.ToastBar;
import static com.codename1.ui.CN.*;
import com.codename1.ui.Form;
import com.codename1.ui.Dialog;
import com.codename1.ui.Label;
import com.codename1.ui.plaf.UIManager;
import com.codename1.ui.util.Resources;
import com.codename1.io.Log;
import com.codename1.ui.Toolbar;
import com.codename1.ui.layouts.BoxLayout;
import com.codename1.io.Util;
import com.codename1.testing.AbstractTest;
import com.codename1.ui.Button;
import com.codename1.ui.CheckBox;
import com.codename1.ui.Command;
import com.codename1.ui.Component;
import static com.codename1.ui.ComponentSelector.$;
import com.codename1.ui.Container;
import com.codename1.ui.events.ActionEvent;
import com.codename1.ui.geom.Dimension;
import com.codename1.ui.layouts.FlowLayout;
import com.codename1.ui.plaf.Border;
import com.codename1.util.AsyncResource;
import com.codename1.util.StringUtil;
import java.util.List;

/**
 * This file was generated by <a href="https://www.codenameone.com/">Codename
 * One</a> for the purpose of building native mobile applications using Java.
 */
public class UnitTests {

    private Form current;
    private Resources theme;

    public void init(Object context) {
        // use two network threads instead of one
        updateNetworkThreadCount(2);

        theme = UIManager.initFirstTheme("/theme");
        UIManager.getInstance().getLookAndFeel().setRTL(true);

        // Enable Toolbar on all Forms by default
        Toolbar.setGlobalToolbar(true);

        // Pro only feature
        Log.bindCrashProtection(true);

        addNetworkErrorListener(err -> {
            // prevent the event from propagating
            err.consume();
            if (err.getError() != null) {
                Log.e(err.getError());
            }
            Log.sendLogAsync();
            Dialog.show("Connection Error", "There was a networking error in the connection to " + err.getConnectionRequest().getUrl(), "OK", null);
        });
    }

    public class TestForm extends Form {

        boolean hebrew = false;

        TestForm() {
            super("Hi World", BoxLayout.y());
            Toolbar tb = new Toolbar();
            Form hi = this;
            hi.setToolbar(tb);
            tb.addCommandToLeftSideMenu(new Command("Test") {
                ;
                public void actionPerformed(ActionEvent e) {
                    System.out.println("Action clicked");
                }
            });

            Button testBoxLayout = new Button("Test Box Layout");
            testBoxLayout.addActionListener(e -> {
                try {
                    boolean result = new BoxLayoutTests().runTest();
                    if (result) {
                        ToastBar.showInfoMessage("Tests passed");
                    } else {
                        ToastBar.showErrorMessage("Tests failed");
                    }
                } catch (Throwable t) {
                    Log.e(t);
                    ToastBar.showErrorMessage("Failed: " + t.getMessage());
                }
            });

            hi.add(testBoxLayout);
            
            Button testStringUtil = new Button("Test String Util");
            testStringUtil.addActionListener(e -> {
                try {
                    boolean result = new StringUtilTests().runTest();
                    if (result) {
                        ToastBar.showInfoMessage("Tests passed");
                    } else {
                        ToastBar.showErrorMessage("Tests failed");
                    }
                } catch (Throwable t) {
                    Log.e(t);
                    ToastBar.showErrorMessage("Failed: " + t.getMessage());
                }
            });

            hi.add(testStringUtil);
            Button testAsyncResource = new Button("Test Async Resource");
            testAsyncResource.addActionListener(e -> {
                try {
                    boolean result = new AsyncResourceTests().runTest();
                    if (result) {
                        ToastBar.showInfoMessage("Tests passed");
                    } else {
                        ToastBar.showErrorMessage("Tests failed");
                    }
                } catch (Throwable t) {
                    Log.e(t);
                    ToastBar.showErrorMessage("Failed: " + t.getMessage());
                }
            });

            hi.add(testAsyncResource);
         

           
            CheckBox rtl = new CheckBox("RTL");
            rtl.setSelected(isRTL());
            rtl.addActionListener(e -> {
                getUIManager().getLookAndFeel().setRTL(rtl.isSelected());
                hebrew = rtl.isSelected();
                //getUIManager().getLookAndFeel().refreshTheme(true);
                new TestForm().show();
                //hi.refreshTheme();
            });
            hi.add(rtl);
            hi.add(new SpanLabel("Test 1: The Labels below should each be rendered centered in its row "));
            hi.add(new SpanLabel("Container paddings (trbl)=(0, 2mm, 2mm, 2mm)"));
            int[] alignments = new int[]{LEFT, RIGHT, CENTER};
            for (int align : alignments) {
                FlowLayout fl = new FlowLayout();
                fl.setAlign(align);
                Container cnt = new Container(fl);
                $(cnt).selectAllStyles()
                        .setBorder(Border.createLineBorder(1))
                        .setPaddingMillimeters(0, 2, 2, 2);
                Label l = new Label();
                $(l).selectAllStyles().setPadding(0).setMargin(0);
                cnt.add(l);
                hi.add(FlowLayout.encloseCenter(cnt));
                l.setText("TEXT" + align);

            }
            hi.add(new SpanLabel("Test 2: The labels below should be be rendered with their appropriate alignment in their row.  Row1=Left, Row2=Right, Row3=Center.  Note that in RTL mode right and left are reversed"));
            hi.add(new SpanLabel("Container paddings (trbl)=(0, 2mm, 2mm, 2mm)"));
            for (int align : alignments) {
                FlowLayout fl = new FlowLayout();
                fl.setAlign(align);
                Container cnt = new Container(fl);
                $(cnt).selectAllStyles()
                        .setBorder(Border.createLineBorder(1))
                        .setPaddingMillimeters(0, 2, 2, 2);
                Label l = new Label();
                $(l).selectAllStyles().setPadding(0).setMargin(0);
                cnt.add(l);
                hi.add(cnt);
                l.setText("TEXT" + align);

            }

            hi.add(new SpanLabel("Test 2a: The labels below should be be rendered with their appropriate alignment in their row.  Row1=Left, Row2=Right, Row3=Center.  Note that in RTL mode right and left are reversed"));
            hi.add(new SpanLabel("Container paddings (trbl)=(0, 1mm, 2mm, 3mm)"));
            for (int align : alignments) {
                FlowLayout fl = new FlowLayout();
                fl.setAlign(align);
                Container cnt = new Container(fl);
                $(cnt).selectAllStyles()
                        .setBorder(Border.createLineBorder(1))
                        .setPaddingMillimeters(0, 1, 2, 3);
                Label l = new Label();
                $(l).selectAllStyles().setPadding(0).setMargin(0);
                cnt.add(l);
                hi.add(cnt);
                l.setText("TEXT" + align);

            }

            hi.add(new SpanLabel("Test 3: Rendering multiple children in a FlowLayout.  The following 3 containers should render their children with the appropriate alignment.  Row 1: Left, Row2 Right, Row3=Center.  Reversed for RTL"));
            hi.add(new SpanLabel("Container paddings (trbl)=(0, 2mm, 2mm, 2mm)"));
            for (int align : alignments) {
                FlowLayout fl = new FlowLayout();
                fl.setAlign(align);
                Container cnt = new Container(fl);
                $(cnt).selectAllStyles()
                        .setBorder(Border.createLineBorder(1))
                        .setPaddingMillimeters(0, 2, 2, 2);
                for (int i = 0; i < 10; i++) {
                    Label l = new Label();
                    $(l).selectAllStyles().setPadding(0).setMargin(0);
                    cnt.add(l);
                    l.setText("TEXT " + align + " " + randomString());
                }

                hi.add(cnt);

            }
            hi.add(new Label("Hi World"));
        }
    }

    public void start() {
        if (current != null) {
            current.show();
            return;
        }

        new TestForm().show();
    }

    static String[] strings = new String[]{
        "Sale on coats",
        "Steve",
        "December",
        "123",
        "A really long sring to see if if fits.  This should probably go over"
    };
    static int nextIndex = 0;

    private static final String randomString() {
        String out = strings[nextIndex];
        nextIndex = (nextIndex + 1) % strings.length;
        return out;
    }

    public void stop() {
        current = getCurrentForm();
        if (current instanceof Dialog) {
            ((Dialog) current).dispose();
            current = getCurrentForm();
        }
    }

    public void destroy() {
    }

    public class StringUtilTests extends AbstractTest {

        @Override
        public boolean runTest() throws Exception {
            String testStr = "1,2,3,,,,,,5,6,3";
            String expected = "[1, 2, 3, 5, 6, 3]";
            //StringTokenizer strtok = new StringTokenizer(testStr, ",");
            //List<String> toks = new ArrayList<>();
            //while (strtok.hasMoreTokens()) {
            //    toks.add(strtok.nextToken());
            //}

            List<String> toks2 = StringUtil.tokenize(testStr, ",");
            assertEqual(expected, toks2.toString());
            return true;
            
        }
        
    }
    
    public class AsyncResourceTests extends AbstractTest {

        @Override
        public boolean runTest() throws Exception {

            AsyncResource r1 = new AsyncResource();
            new Thread(() -> {
                Util.sleep(100);
                r1.complete(new Integer(1));
            }).start();
            assertTrue(!r1.isCancelled());
            assertTrue(!r1.isDone());
            assertTrue(!r1.isReady());
            assertEqual(new Integer(0), r1.get(new Integer(0)));
            AsyncResource.await(r1);
            assertTrue(r1.isDone());
            assertTrue(r1.isReady());
            assertEqual(new Integer(1), r1.get(new Integer(0)));
            assertEqual(new Integer(1), r1.get());
            Integer[] val = new Integer[1];
            r1.ready(o -> {
                val[0] = (Integer) o;
            });
            assertEqual(new Integer(1), val[0]);
            val[0] = null;
            r1.ready(o -> {
                val[0] = (Integer) o;
            });
            assertEqual(new Integer(1), val[0]);

            // Now test all() to make sure that its ready fires when all components are ready.
            AsyncResource r2 = new AsyncResource();
            AsyncResource r3 = new AsyncResource();
            AsyncResource r4 = AsyncResource.all(r2, r3);
            assertTrue(!r2.isDone());
            assertTrue(!r3.isDone());
            assertTrue(!r4.isDone());

            r2.complete(new Integer(1));
            assertTrue(r2.isDone());
            assertTrue(r2.isReady());
            assertTrue(!r3.isDone());
            assertTrue(!r3.isReady());
            assertTrue(!r4.isDone());
            assertTrue(!r4.isReady());
            r3.complete(new Integer(2));
            assertTrue(r3.isReady());
            assertTrue(r3.isDone());
            assertTrue(r4.isReady());
            assertTrue(r4.isDone());

            AsyncResource r5 = new AsyncResource();
            AsyncResource r6 = new AsyncResource();
            AsyncResource r7 = AsyncResource.all(r5, r6);
            r5.complete(new Integer(1));
            r6.error(new RuntimeException("Foo"));
            assertTrue(!r7.isReady());
            assertTrue(r7.isDone());
            Throwable[] t7 = new Throwable[1];
            r7.except(ex -> {
                t7[0] = (Throwable) ex;
            });
            assertTrue(t7[0] != null);
            t7[0] = null;
            try {
                r7.get();
            } catch (Throwable ex) {
                t7[0] = ex;
            }
            assertTrue(t7[0] != null);
            t7[0] = null;
            try {
                AsyncResource.await(r7);
            } catch (Throwable ex) {
                t7[0] = ex;
            }
            assertTrue(t7[0] != null);

            return true;
        }

    }

    public class BoxLayoutTests extends AbstractTest {

        @Override
        public boolean runTest() throws Exception {
            BoxLayout l = new BoxLayout(BoxLayout.Y_AXIS);
            Container cnt = new Container(l);
            cnt.setRTL(false);
            int w = 500;
            int h = 500;

            cnt.setWidth(w);
            cnt.setHeight(h);

            Component child1 = createEmptyComponent(100, 100);
            Component child2 = createEmptyComponent(200, 50);
            cnt.add(child1).add(child2);

            $(child1, child2, cnt).setPadding(0).setMargin(0);
            cnt.layoutContainer();
            assertEqual(0, child1.getY(), "child1 should be aligned top");
            assertEqual(100, child2.getY(), "child 2 should be aligned top just after child1 ");
            assertEqual(0, child1.getX(), "Child1 not aligned left");
            assertEqual(w, child1.getWidth(), "Child1 not taking full width");
            assertEqual(0, child2.getX(), "Child2 not aligned left");
            assertEqual(w, child2.getWidth(), "Child2 not taking full width");

            l.setAlign(BOTTOM);
            cnt.setShouldCalcPreferredSize(true);
            cnt.layoutContainer();
            assertEqual(500, child2.getY() + child2.getHeight(), "Child2 should be aligned bottom");
            assertEqual(450, child1.getY() + child1.getHeight(), "child 1 should be aligned bottom just above child2");
            assertEqual(0, child1.getX(), "Child1 not aligned left");
            assertEqual(w, child1.getWidth(), "Child1 not taking full width");
            assertEqual(0, child2.getX(), "Child2 not aligned left");
            assertEqual(w, child2.getWidth(), "Child2 not taking full width");

            l.setAlign(CENTER);
            cnt.setShouldCalcPreferredSize(true);
            cnt.layoutContainer();
            assertEqual(325, child2.getY() + child2.getHeight(), "Child2 should be aligned bottom");
            assertEqual(175, child1.getY(), "child 1 should be aligned bottom just above child2");
            assertEqual(0, child1.getX(), "Child1 not aligned left");
            assertEqual(w, child1.getWidth(), "Child1 not taking full width");
            assertEqual(0, child2.getX(), "Child2 not aligned left");
            assertEqual(w, child2.getWidth(), "Child2 not taking full width");

            Component child3 = createEmptyComponent(500, 500);
            $(child3).setPadding(0).setMargin(0);
            cnt.add(child3);
            // This is a component to tip it over the edge.

            // NOTICE:  When the children fill the height of the container, the align property
            // ceases to have meaning.  We do NOT try to align the components once the container is filled.
            cnt.setShouldCalcPreferredSize(true);
            cnt.layoutContainer();
            assertEqual(0, child1.getY(), "Child1 should be aligned top");
            assertEqual(100, child2.getY(), "Child 2 should be aligned just after");
            assertEqual(150, child3.getY(), "Child 3 should be just after");

            assertEqual(0, child1.getX(), "Child1 not aligned left");
            assertEqual(w, child1.getWidth(), "Child1 not taking full width");
            assertEqual(0, child2.getX(), "Child2 not aligned left");
            assertEqual(w, child2.getWidth(), "Child2 not taking full width");

            l.setAlign(BOTTOM);
            cnt.setShouldCalcPreferredSize(true);
            cnt.layoutContainer();
            assertEqual(0, child1.getY(), "Child1 should be aligned top");
            assertEqual(100, child2.getY(), "Child 2 should be aligned just after");
            assertEqual(150, child3.getY(), "Child 3 should be just after");

            assertEqual(0, child1.getX(), "Child1 not aligned left");
            assertEqual(w, child1.getWidth(), "Child1 not taking full width");
            assertEqual(0, child2.getX(), "Child2 not aligned left");
            assertEqual(w, child2.getWidth(), "Child2 not taking full width");

            //Now test the x axis
            l = BoxLayout.x();
            cnt.setLayout(l);
            cnt.removeComponent(child3);
            cnt.setShouldCalcPreferredSize(true);
            cnt.layoutContainer();

            assertEqual(0, child1.getX(), "Child1 not aligned left");
            assertEqual(100, child1.getWidth(), "Child2 not taking preferred width");
            assertEqual(h, child1.getHeight(), "Child1 not taking full height");
            assertEqual(0, child1.getY(), "Child1 not aligning top");
            assertEqual(100, child2.getX(), "Child2 should be aligned next to child1");
            assertEqual(200, child2.getWidth(), "Child 2 not taking preferred width");
            assertEqual(h, child2.getHeight(), "Child 2 not taking full height of container");
            assertEqual(0, child2.getY(), "Child2 not aligning top");

            l.setAlign(CENTER);
            cnt.setShouldCalcPreferredSize(true);
            cnt.layoutContainer();

            assertEqual(100, child1.getX(), "Child1 not aligned left");
            assertEqual(100, child1.getWidth(), "Child2 not taking preferred width");
            assertEqual(h, child1.getHeight(), "Child1 not taking full height");
            assertEqual(0, child1.getY(), "Child1 not aligning top");
            assertEqual(200, child2.getX(), "Child2 should be aligned next to child1");
            assertEqual(200, child2.getWidth(), "Child 2 not taking preferred width");
            assertEqual(h, child2.getHeight(), "Child 2 not taking full height of container");
            assertEqual(0, child2.getY(), "Child2 not aligning top");

            l.setAlign(RIGHT);
            cnt.setShouldCalcPreferredSize(true);
            cnt.layoutContainer();

            assertEqual(200, child1.getX(), "Child1 not aligned left");
            assertEqual(100, child1.getWidth(), "Child2 not taking preferred width");
            assertEqual(h, child1.getHeight(), "Child1 not taking full height");
            assertEqual(0, child1.getY(), "Child1 not aligning top");
            assertEqual(300, child2.getX(), "Child2 should be aligned next to child1");
            assertEqual(200, child2.getWidth(), "Child 2 not taking preferred width");
            assertEqual(h, child2.getHeight(), "Child 2 not taking full height of container");
            assertEqual(0, child2.getY(), "Child2 not aligning top");

            return true;
        }

        private Component createEmptyComponent(int width, int height) {
            return new Component() {
                @Override
                protected Dimension calcPreferredSize() {
                    return new Dimension(width, height);
                }

            };
        }

    }

    
}
